﻿Public Class SimulateInput
    Private Declare Sub mouse_event Lib "user32" Alias "mouse_event" (ByVal dwFlags As Integer, ByVal dx As Integer, ByVal dy As Integer, ByVal cButtons As Integer, ByVal dwExtraInfo As Integer)
    Private Declare Function SetCursorPos Lib "user32" (ByVal X As Integer, ByVal Y As Integer) As Integer
    Private Declare Function GetCursorPos Lib "user32" (ByVal lpPoint As POINTAPI) As Integer
    Private Const MOUSEEVENTF_LEFTDOWN = &H2
    Private Const MOUSEEVENTF_LEFTUP = &H4
    Private Const MOUSEEVENTF_MIDDLEDOWN = &H20
    Private Const MOUSEEVENTF_MIDDLEUP = &H40
    Private Const MOUSEEVENTF_RIGHTDOWN = &H8
    Private Const MOUSEEVENTF_RIGHTUP = &H10
    Private Const MOUSEEVENTF_MOVE = &H1

    Private m_left As Boolean
    Private m_right As Boolean
    Private m_middle As Boolean

    Private Structure POINTAPI
        Dim X As Integer
        Dim Y As Integer
    End Structure

    Private m_storedOffset As PointF

    Public Sub New()
        m_storedOffset = PointF.Empty
        m_left = False
        m_right = False
        m_middle = False
    End Sub

    ''' <summary>
    ''' Moves the mouse by the specified amount.
    ''' </summary>
    ''' <param name="pt"></param>
    ''' <returns>Whether or not the mouse went passed the boundary.</returns>
    ''' <remarks></remarks>/
    Public Function MoveMouse(ByVal pt As PointF) As Boolean
        'Update stored offset and store small less than one remainders for next time.
        m_storedOffset = New PointF(pt.X + m_storedOffset.X, pt.Y + m_storedOffset.Y)

        Dim x As Integer = m_storedOffset.X
        Dim y As Integer = m_storedOffset.Y

        m_storedOffset = New PointF(m_storedOffset.X - x, m_storedOffset.Y - y)

        Dim current As Point = Cursor.Position
        Dim newPt As Point = New Point(current.X + x, current.Y + y)

        Dim result As Boolean = False

        Dim clip As Rectangle = Cursor.Clip

        If newPt.X < clip.Left Then
            result = True
            newPt.X = clip.Left
        End If

        If newPt.Y < clip.Top Then
            result = True
            newPt.Y = clip.Top
        End If

        If newPt.X > clip.Right Then
            result = True
            newPt.X = clip.Right
        End If

        If newPt.Y > clip.Bottom Then
            result = True
            newPt.Y = clip.Bottom
        End If

        Cursor.Position = newPt

        Return result
    End Function

    ''' <summary>
    ''' Moves the mouse by the specified amount.
    ''' </summary>
    ''' <param name="x"></param>
    ''' <param name="y"></param>
    ''' <returns>Whether or not the mouse went passed the boundary.</returns>
    ''' <remarks></remarks>/
    Public Function MoveMouse(ByVal x As Double, ByVal y As Double) As Boolean
        Return MoveMouse(New PointF(x, y))
    End Function

    Public Sub SetMouseButtonState(ByVal button As MouseButtons, ByVal state As Boolean)
        Select Case button
            Case MouseButtons.Left
                If m_left = state Then
                    Return
                End If
                m_left = state

                If state Then
                    'Added for Debug
                    'Beep()
                    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
                Else
                    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
                End If

            Case MouseButtons.Middle
                If m_middle = state Then
                    Return
                End If
                m_middle = state

                If state Then
                    mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0)
                Else
                    mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0)
                End If

            Case MouseButtons.Right
                If m_right = state Then
                    Return
                End If
                m_right = state

                If state Then
                    mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
                Else
                    mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)
                End If

        End Select
    End Sub
End Class
